package com.knowswift.security.filter;

import com.knowswift.common.common.Assert;
import com.knowswift.common.utils.JSONUtils;
import com.knowswift.security.exception.AuthException;
import com.knowswift.security.param.AccountParam;
import lombok.SneakyThrows;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;

/**
 * @company https://www.knowswift.com
 * 账号密码登录拦截器
 */
public class PasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private final Class<? extends UsernamePasswordAuthenticationToken> auth;

    public PasswordAuthenticationFilter(String loginPattern, Class<? extends UsernamePasswordAuthenticationToken> auth) {
        super(new AntPathRequestMatcher(loginPattern, "POST"));
        setSessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
        this.auth = auth;
    }


    @Override
    public void afterPropertiesSet() {
        Assert.notNull(getAuthenticationManager(), "authenticationManager must be specified");
        Assert.notNull(getSuccessHandler(), "AuthenticationSuccessHandler must be specified");
        Assert.notNull(getFailureHandler(), "AuthenticationFailureHandler must be specified");
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
        // 获取参数中的账号密码
        if (!StringUtils.hasText(body)) {
            throw new AuthException(300, "请输入账号密码");
        }
        AccountParam param = JSONUtils.parseObject(body, AccountParam.class);

        if (!StringUtils.hasText(param.getAccount())) {
            throw new AuthException(300, "请输入账号");
        }
        if (!StringUtils.hasText(param.getPassword())) {
            throw new AuthException(300, "请输入密码");
        }

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                auth.getConstructor(Object.class, Object.class, String.class)
                        .newInstance(param.getAccount(), param.getPassword(), param.getAppleId());

        try {
            // 调用登录方法：provider
            Authentication authenticate = this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);

            return auth.getConstructor(Object.class, Object.class, String.class)
                    .newInstance(authenticate.getPrincipal(), authenticate.getCredentials(), param.getAppleId());
        } catch (BadCredentialsException b) {
            throw new AuthException(300, "密码错误");
        } catch (LockedException l) {
            throw new AuthException(300, "账号已被冻结");
        }
    }

}
